using System;
using System.Collections.Generic;
using System.Text;

namespace EuropeEngulfed.NET
{
    class RemoteGameController : GameController
    {
        private TCPClient clientConnection;
        private bool connected;
        private IPlayer localPlayer;

        public bool Connected
        {
            get
            {
                return connected;
            }
        }

        public RemoteGameController(TCPClient clientConnection, IPlayer localPlayer)
        {
            this.clientConnection = clientConnection;
            connected = clientConnection.Connect();
            if (connected)
            {
                currentEuropeEngulfedGameState = this.clientConnection.GetLatestGameState(TCPClient.UNKNOWN_GAME_DATE);
            }
            else
                currentEuropeEngulfedGameState = new GameState();
            this.localPlayer = localPlayer;
        }

        public bool Connect()
        {
            if (!connected)
            {
                if (clientConnection.Connect())
                    return true;
                else
                    return false;
            }
            else
                return true;
        }

        public override void Start39CampaignGame()
        {
            currentEuropeEngulfedGameState = this.clientConnection.GetLatestGameState(TCPClient.UNKNOWN_GAME_DATE);
        }

        public override Dictionary<PlayingPiece, int> AskAttackerToAssignLosses(GameController.playerType attackingPlayer, MapInfo.RegionID battleRegionID, bool assault, Dictionary<MapInfo.CountryID, int> defendingGSUSelections, Dictionary<MapInfo.CountryID, int> attackingGSUSelections, int numInfantryLosses, int numArmorLosses, bool counterAttack, List<MapInfo.CountryID> countriesSpendingSAInBattle, List<CombatMove> combatMovesAlreadyTaken)
        {
            try
            {
                ServerMessageAssignLossesReturn returnMessage = (ServerMessageAssignLossesReturn)clientConnection.SendClientMessage(new ClientMessageAskAttackerToAssignLosses(attackingPlayer, battleRegionID, assault, defendingGSUSelections, attackingGSUSelections, numInfantryLosses, numArmorLosses, counterAttack, countriesSpendingSAInBattle, combatMovesAlreadyTaken), TCPClient.ClientMessageType.AssignLossesReturn, localPlayer);
                return returnMessage.losses;
            }
            catch(Exception e)
            {
                throw new ApplicationException("Error Communicating with the EE.NET server." + e.ToString());
            }
        }

        public override Dictionary<PlayingPiece, int> AskAttackerToAssignLosses(GameController.playerType attackingPlayer, MapInfo.RegionID regionID, bool assault, Dictionary<MapInfo.CountryID, int> defendingGSUSelections, Dictionary<MapInfo.CountryID, int> attackingGSUSelections, int numInfantryLosses, int numArmorLosses, bool counterAttack, List<CombatMove> combatMovesAlreadyTaken)
        {
            return AskAttackerToAssignLosses(attackingPlayer, regionID, assault, defendingGSUSelections, attackingGSUSelections, numInfantryLosses, numArmorLosses, counterAttack, null, combatMovesAlreadyTaken);
        }

        public override bool DetermineStrategicWarInterception(GameController.playerType player)
        {
            try
            {
                ServerMessageAssignBoolReturn returnMessage = (ServerMessageAssignBoolReturn)clientConnection.SendClientMessage(new ClientMessageDetermineStrategicWarInterception(player), TCPClient.ClientMessageType.boolReturn, localPlayer);
                return returnMessage.returnValue;
            }
            catch (Exception e)
            {
                throw new ApplicationException("Error Communicating with the EE.NET server." + e.ToString());
            }
        }

        public override List<DeploymentMove> AskForNewCountryDeployment(GameController.playerType player, MapInfo.CountryID country)
        {
            try
            {
                ServerMessageDeploymentMovesReturn returnMessage = (ServerMessageDeploymentMovesReturn)clientConnection.SendClientMessage(new ClientMessageAskForNewCountryDeployment(player, country), TCPClient.ClientMessageType.DeploymentMovesReturn, localPlayer);
                return returnMessage.returnValue;
            }
            catch (Exception e)
            {
                throw new ApplicationException("Error Communicating with the EE.NET server." + e.ToString());
            }
        }

        public override bool AskForNavalInterception(GameController.playerType player, SeaMoveOperationalMove seaMove)
        {
            try
            {
                ServerMessageAssignBoolReturn returnMessage = (ServerMessageAssignBoolReturn)clientConnection.SendClientMessage(new ClientMessageAskForNavalInterception(player, seaMove), TCPClient.ClientMessageType.boolReturn, localPlayer);
                return returnMessage.returnValue;
            }
            catch (Exception e)
            {
                throw new ApplicationException("Error Communicating with the EE.NET server." + e.ToString());
            }
        }

        public override bool ReportNavalInterception(GameController.playerType player, MapInfo.RegionID regionID, int numFriendlyHitsOn6, int numFriendlyHitsOn56, int numEnemyHitsOn6, int numEnemyHitsOn56, List<PlayingPiece> piecesTransported, List<PlayingPiece> piecesLost)
        {
            try
            {
                ServerMessageAssignBoolReturn returnMessage = (ServerMessageAssignBoolReturn)clientConnection.SendClientMessage(new ClientMessageReportForNavalInterception(player, regionID, numFriendlyHitsOn6, numFriendlyHitsOn56, numEnemyHitsOn6, numEnemyHitsOn56, piecesTransported, piecesLost), TCPClient.ClientMessageType.boolReturn, localPlayer);
                return returnMessage.returnValue;
            }
            catch (Exception e)
            {
                throw new ApplicationException("Error Communicating with the EE.NET server." + e.ToString());
            }
        }

        public override defenderOptions AskDefenderForDefenderOptions(GameController.playerType defendingPlayer, MapInfo.RegionID regionID, bool selectGSUs, bool breakThroughCombat, bool assault, List<MapInfo.CountryID> countriesSpendingSA, List<CombatMove> combatMovesAlreadyTaken)
        {
            try
            {
                ServerMessageAskForDefenderOptionsReturn returnMessage = (ServerMessageAskForDefenderOptionsReturn)clientConnection.SendClientMessage(new ClientMessageAskDefenderForDefenderOptions(defendingPlayer, regionID, selectGSUs, breakThroughCombat, assault, countriesSpendingSA, combatMovesAlreadyTaken), TCPClient.ClientMessageType.AskForDefenderOptionsReturn, localPlayer);
                return returnMessage.defenderOptions;
            }
            catch (Exception e)
            {
                throw new ApplicationException("Error Communicating with the EE.NET server." + e.ToString());
            }
        }

        public override List<OperationalMove> AskDefenderForRetreatBeforeCombatMoves(GameController.playerType defendingPlayer, MapInfo.RegionID regionID, List<CombatMove> combatMovesAlreadyTaken)
        {
            try
            {
                ServerMessageAskDefenderForRetreatBeforeCombatMovesReturn returnMessage = (ServerMessageAskDefenderForRetreatBeforeCombatMovesReturn)clientConnection.SendClientMessage(new ClientMessageAskDefenderForRetreatBeforeCombatMoves(defendingPlayer, regionID, combatMovesAlreadyTaken), TCPClient.ClientMessageType.AskDefenderForRetreatBeforeCombatMovesReturn, localPlayer);
                return returnMessage.listOfOpMoves;
            }
            catch (Exception e)
            {
                throw new ApplicationException("Error Communicating with the EE.NET server." + e.ToString());
            }
        }

        public override Dictionary<MapInfo.CountryID, int> AskForGSUCombatCasualties(GameController.playerType playerAssigningCasualties, GameController.playerType defendingPlayer, MapInfo.RegionID regionID, Dictionary<MapInfo.CountryID, int> defendingGSUSelections, Dictionary<MapInfo.CountryID, int> attackingGSUSelections, List<int> defendingDieRolls, List<int> attackingDieRolls, bool breakThrough, List<MapInfo.CountryID> countriesSpendingSA)
        {
            try
            {
                ServerMessageAskForGSUCombatCasualtiesReturn returnMessage = (ServerMessageAskForGSUCombatCasualtiesReturn)clientConnection.SendClientMessage(new ClientMessageAskForGSUCombatCasualties(playerAssigningCasualties, defendingPlayer, regionID, defendingGSUSelections, attackingGSUSelections, defendingDieRolls, attackingDieRolls, breakThrough, countriesSpendingSA), TCPClient.ClientMessageType.AskForGSUCombatCasualtiesReturn, localPlayer);
                return returnMessage.listOfGSUCombatCasualties;
            }
            catch (Exception e)
            {
                throw new ApplicationException("Error Communicating with the EE.NET server." + e.ToString());
            }
        }

        public override Dictionary<PlayingPiece, int> DoDefenderCombat(GameController.playerType defendingPlayer, MapInfo.RegionID battleRegionID, bool assault, Dictionary<MapInfo.CountryID, int> defendingGSUSelections, Dictionary<MapInfo.CountryID, int> attackingGSUSelections, bool counterAttack, List<CombatMove> combatMovesAlreadyTaken)
        {
            try
            {
                ServerMessageAssignLossesReturn returnMessage = (ServerMessageAssignLossesReturn)clientConnection.SendClientMessage(new ClientMessageDoDefenderCombat(defendingPlayer, battleRegionID, assault, defendingGSUSelections, attackingGSUSelections, counterAttack, combatMovesAlreadyTaken), TCPClient.ClientMessageType.AssignLossesReturn, localPlayer);
                return returnMessage.losses;
            }
            catch (Exception e)
            {
                throw new ApplicationException("Error Communicating with the EE.NET server." + e.ToString());
            }
        }

        public override Dictionary<PlayingPiece, int> DoDefenderBreakThroughCombat(GameController.playerType defendingPlayer, MapInfo.RegionID regionID, bool assault, Dictionary<MapInfo.CountryID, int> defendingGSUSelections, Dictionary<MapInfo.CountryID, int> attackingGSUSelections, bool counterAttack, List<MapInfo.CountryID> countriesSpendingSAForBreakThroughCombat, List<CombatMove> combatMovesAlreadyTaken)
        {
            try
            {
                ServerMessageAssignLossesReturn returnMessage = (ServerMessageAssignLossesReturn)clientConnection.SendClientMessage(new ClientMessageDoDefenderBreakThroughCombat(defendingPlayer, regionID, assault, defendingGSUSelections, attackingGSUSelections, counterAttack, countriesSpendingSAForBreakThroughCombat, combatMovesAlreadyTaken), TCPClient.ClientMessageType.AssignLossesReturn, localPlayer);
                return returnMessage.losses;
            }
            catch (Exception e)
            {
                throw new ApplicationException("Error Communicating with the EE.NET server." + e.ToString());
            }
        }

        public override Dictionary<PlayingPiece, int> AskDefenderToAssignLosses(GameController.playerType defendingPlayer, MapInfo.RegionID battleRegionID, bool assault, Dictionary<MapInfo.CountryID, int> defendingGSUSelections, Dictionary<MapInfo.CountryID, int> attackingGSUSelections, int numInfantryLosses, int numArmorLosses, bool counterAttack, List<CombatMove> combatMovesAlreadyTaken)
        {
            try
            {
                ServerMessageAssignLossesReturn returnMessage = (ServerMessageAssignLossesReturn)clientConnection.SendClientMessage(new ClientMessageAskDefenderToAssignLosses(defendingPlayer, battleRegionID, assault, defendingGSUSelections, attackingGSUSelections, numInfantryLosses, numArmorLosses, counterAttack, combatMovesAlreadyTaken), TCPClient.ClientMessageType.AssignLossesReturn, localPlayer);
                return returnMessage.losses;
            }
            catch (Exception e)
            {
                throw new ApplicationException("Error Communicating with the EE.NET server." + e.ToString());
            }
        }

        public override defenderCounterAttackOptions AskDefenderForCounterAttack(GameController.playerType defendingPlayer, MapInfo.RegionID battleRegion, List<CombatMove> combatMovesAlreadyTaken)
        {
            try
            {
                ServerMessageAskDefenderForCounterAttackReturn returnMessage = (ServerMessageAskDefenderForCounterAttackReturn)clientConnection.SendClientMessage(new ClientMessageAskDefenderForCounterAttack(defendingPlayer, battleRegion, combatMovesAlreadyTaken), TCPClient.ClientMessageType.AskDefenderForCounterAttackReturn, localPlayer);
                return returnMessage.counterAttackOptions;
            }
            catch (Exception e)
            {
                throw new ApplicationException("Error Communicating with the EE.NET server." + e.ToString());
            }
        }

        public void PollRemoteServer(IPlayer player)
        {
            string messageParams = "";
            switch (clientConnection.PollTCPServer(ref messageParams))
            {
                case TCPClient.ClientMessageType.OK:
                    break;
                case TCPClient.ClientMessageType.DoDefenderCombat:
                case TCPClient.ClientMessageType.DisplayWeather:
                case TCPClient.ClientMessageType.DisplayCalculatingSupply:
                case TCPClient.ClientMessageType.AskForDefenderOptions:
                case TCPClient.ClientMessageType.AskDefenderToAssignLosses:
                case TCPClient.ClientMessageType.AskDefenderForCounterAttack:
                case TCPClient.ClientMessageType.DoStrategicBombingWarfare:
                case TCPClient.ClientMessageType.DoStrategicUBoatWarfare:
                case TCPClient.ClientMessageType.DoStrategicVWeaponWarfare:
                case TCPClient.ClientMessageType.DoAxisProductionPhase:
                case TCPClient.ClientMessageType.DoAlliedProductionPhase:
                case TCPClient.ClientMessageType.AskForStrategicWarfareInterception:
                case TCPClient.ClientMessageType.DoSupplySelection:
                case TCPClient.ClientMessageType.DoInitialOps:
                case TCPClient.ClientMessageType.DoBreakThroughOps:
                case TCPClient.ClientMessageType.DoInitialStrategicMovement:
                case TCPClient.ClientMessageType.DoNewCountryDeployment:
                case TCPClient.ClientMessageType.AskForNavalInterception:
                case TCPClient.ClientMessageType.DoBreakThroughCombat:
                case TCPClient.ClientMessageType.DoInitialCombatPhase:
                case TCPClient.ClientMessageType.AskForGSUCombatCasualties:
                case TCPClient.ClientMessageType.AskAttackerToAssignLosses:
                case TCPClient.ClientMessageType.AskDefenderForRetreatBeforeCombatMoves:
                case TCPClient.ClientMessageType.AskForBreakThroughOption:
                case TCPClient.ClientMessageType.DoBreakThroughStrategicMovement:
                case TCPClient.ClientMessageType.InformPlayerOfConquest:
                case TCPClient.ClientMessageType.DoFleetPointTransfers:
                case TCPClient.ClientMessageType.DoFortressOverStackMoves:
                case TCPClient.ClientMessageType.AskAxisPlayerForVichy:
                case TCPClient.ClientMessageType.InformPlayer:
                case TCPClient.ClientMessageType.DoAxisRedeploymentOfSovietUpFrontDefenses:
                case TCPClient.ClientMessageType.InformPlayerOfVictory:
                case TCPClient.ClientMessageType.InformPlayerOfChangeOfPhase:
                case TCPClient.ClientMessageType.ReportStrategicUBoatWarfare:
                case TCPClient.ClientMessageType.ReportStrategicBombingWarfare:
                case TCPClient.ClientMessageType.ReportStrategicVWeaponWarfare:
                case TCPClient.ClientMessageType.ReportForNavalInterception:
                    {
                        GameState remoteGameState = null;
                        ClientMessage clientMessageToReturn = null;
                        System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
                        xmlDoc.Load(System.Xml.XmlReader.Create(new System.IO.StringReader(messageParams)));
                        remoteGameState = this.clientConnection.GetLatestGameState(Enum.GetName(typeof(GameTurn.GameDate), currentEuropeEngulfedGameState.CurrentGameTurn.CurrentGameDate));
                        remoteGameState.MergeGameStateMoves(currentEuropeEngulfedGameState);
                        currentEuropeEngulfedGameState = remoteGameState;
                        if ((clientMessageToReturn = ((ServerMessagePlayerCall)ServerMessage.Deserialise(xmlDoc.FirstChild)).CallPlayer(player)) != null)
                            clientConnection.ReturnClientMessage(clientMessageToReturn);
                    }
                    break;
            }
        }

        public void MergeUpdatedGameState(GameState currentGameState)
        {           
            currentGameState.MergeGameStateMoves(currentEuropeEngulfedGameState);
            currentEuropeEngulfedGameState = currentGameState;
        }
    }
}
